package com.tanhua.server.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.dozermapper.core.Mapper;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.User;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.dto.MovementDto;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.service.MovementService;
import com.tanhua.server.service.MqMessageService;
import com.tanhua.server.service.UserFreezeService;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author wjs
 * @version 1.0
 * @date 2021/12/26 0026 上午 11:48
 */
@Service
public class MovementServiceImpl implements MovementService {

    @Autowired
    Mapper mapper;

    @DubboReference
    private MovementApi movementApi;

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private RedisTemplate redisTemplate;

    @DubboReference
    private VisitorsApi visitorsApi;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private UserApi userApi;

    @Autowired
    private UserFreezeService userFreezeService;

//    @Autowired
//    private AmqpTemplate amqpTemplate;
    @Autowired
    private MqMessageService mqMessageService;

    //发布动态
    @Override
    public void publishMovement(MovementDto movementDto, MultipartFile[] imageContent) {

        //校验用户状态--------------------------
        User user = userApi.findById(UserHolder.getUserId());
        if (user != null) {
            userFreezeService.checkUserStatus(3,user.getId());
        }

        if (StringUtils.isEmpty(movementDto.getTextContent())) {
            throw new BusinessException(ErrorResult.contentError());
        }

        //获取当前登录的用户id
        Long userId = UserHolder.getUserId();

        //将文件内容上传到阿里云OSS，获取请求地址
        List<String> medias = Arrays.stream(imageContent).map((multipartFile) -> {
            String upload = null;
            try {
                upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return upload;
        }).collect(Collectors.toList());

        //将数据封装到Movement对象
        Movement movement = mapper.map(movementDto, Movement.class);
        movement.setLocationName(movementDto.getLocation());
        movement.setUserId(userId);
        movement.setMedias(medias);

        //调用API完成发布动态
        Movement publish = movementApi.publish(movement);

        //发送动态审核消息
//        amqpTemplate.convertSendAndReceive("tanhua.audit.exchange", "audit.movement", publish.getId().toHexString());
        mqMessageService.sendAudiMessage(publish.getId().toHexString());
    }

    //查询我的动态
    @Override
    public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
        PageResult pageResult = movementApi.pageByUserId(userId, page, pagesize);

        List<Movement> items = (List<Movement>) pageResult.getItems();

        if (items == null || items.size() == 0) {
            return pageResult;
        }

        UserInfo userInfo = userInfoApi.findById(userId);
        List<MovementsVo> vos = items.stream().map(item -> {
            return MovementsVo.init(userInfo, item);
        }).collect(Collectors.toList());

        pageResult.setItems(vos);

        return new PageResult(page, pagesize, 0L, vos);
    }

    //查询好友动态
    @Override
    public PageResult findFriendMovements(Integer page, Integer pagesize) {

        //1、获取当前用户的id
        Long userId = UserHolder.getUserId();
        //2、调用API查询当前用户好友发布的动态列表
        List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
        return getPageResult(page, pagesize, list);
    }

    @Override
    public PageResult findRecommendMovements(Integer page, Integer pagesize) {

        //获取redis中的推荐数据
        Long userId = UserHolder.getUserId();
        String redisValue = (String) redisTemplate.opsForValue().get(Constants.MOVEMENTS_RECOMMEND + userId);

        //判断推荐数据是否存在
        List<Movement> list = new ArrayList<>();
        if (redisValue == null || redisValue.isEmpty()) {
            //如果不存在，调用API随机构造 pagesize 条动态数据
            list = movementApi.randomMovents(pagesize, userId);
        } else {
            //如果存在，处理pid数据
            String[] values = redisValue.split(",");

            //判断当前页的起始条数是否小于数组总数,大于0
            if ((page - 1) * pagesize > 0 && (page - 1) * pagesize <= pagesize) {
                //如果小于数组总数,大于0进行分组(分页)操作
                List<Long> pids = Arrays.stream(values).skip((page - 1) * pagesize)
                        .limit(pagesize)
                        .map(value -> Long.valueOf(value))
                        .collect(Collectors.toList());
                //调用API根据pids获取Movement集合
                list = movementApi.findMovementsByPids(pids);
            } else {
                //如果大于数组总数,小于0,调用API随机构造 pagesize 条动态数据
                list = movementApi.randomMovents(pagesize, userId);
            }
        }

        return getPageResult(page, pagesize, list);
    }

    @Override
    public MovementsVo findById(String movementId) {
        //发送消息
        mqMessageService.sendLogMessage(UserHolder.getUserId(),"0202","movement",movementId);
        //1、调用api根据id查询动态详情
        Movement movement = movementApi.findById(movementId);
        //2、转化vo对象
        if (movement != null) {
            UserInfo userInfo = userInfoApi.findById(movement.getUserId());
            return MovementsVo.init(userInfo, movement);
        } else {
            return null;
        }
    }

    @Override
    public Integer addLike(String movementId) {
        //调用API查询用户是否已点赞
        Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);

        if (hasComment) {
            throw new BusinessException(ErrorResult.likeError());
        }

        //将点赞保存到comment表中,并修改movement中likeCount(加1)
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        Integer count = commentApi.save(comment);

        //拼接redis的key，将用户的点赞状态存入redis
        //大键key,小键hashKey,值1(现在还不知道用处,以后可能用到)
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key, hashKey, "1");
        return count;
    }

    @Override
    public Integer disLike(String movementId) {
        //调用API查询用户是否已点赞
        Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);

        if (!hasComment) {
            throw new BusinessException(ErrorResult.likeError());
        }

        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getUserId());
        Integer count = commentApi.delete(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().delete(key, hashKey);

        return count;
    }

    @Override
    public Integer addLove(String movementId) {
        //1、调用API查询用户是否已点赞
        Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LOVE);
        //2、如果已经喜欢，抛出异常
        if (hasComment) {
            throw new BusinessException(ErrorResult.loveError());
        }
        //3、调用API保存数据到Mongodb
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        Integer count = commentApi.save(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key, hashKey, "1");
        return count;
    }

    @Override
    public Integer unLove(String movementId) {
        //调用API查询用户是否已点赞
        Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);

        if (!hasComment) {
            throw new BusinessException(ErrorResult.likeError());
        }

        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getUserId());
        Integer count = commentApi.delete(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().delete(key, hashKey);

        return count;
    }

    @Override
    public List<VisitorsVo> queryVisitorsList() {

        //查询上一次查询访问列表时间
        String key = Constants.VISITORS_USER;
        String hashKey = UserHolder.getUserId().toString();
        Object o = redisTemplate.opsForHash().get(key, hashKey);
        String value = o == null ? null : o.toString();
        Long date = StringUtils.isEmpty(value) ? null : Long.valueOf(value);

        //获取Visitors集合
        List<Visitors> list = visitorsApi.queryMyVisitors(date, UserHolder.getUserId());
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //提取访问者用户的id
        List<Long> userIds = list.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());
        if (userIds == null || userIds.isEmpty()) {
            return new ArrayList<>();
        }
        //查询访问者用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
        //构造返回
        List<VisitorsVo> vos = list.stream().filter(visitor -> map.get(visitor.getVisitorUserId()) != null)
                .map(visitor -> VisitorsVo.init(map.get(visitor.getVisitorUserId()), visitor))
                .collect(Collectors.toList());

        //设置当前查询访问列表时间
        redisTemplate.opsForHash().put(key, hashKey, System.currentTimeMillis());
        return vos;
    }

    private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
        //3、判断列表是否为空
        if (list == null || list.size() == 0) {
            return new PageResult();
        }

        List<Long> userIds = list.stream().map(movement -> movement.getUserId()).collect(Collectors.toList());
        //根据用户的id列表获取用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);

        List<MovementsVo> vos = list.stream()
                .filter(movement -> map.get(movement.getUserId()) != null)
                .map(movement -> {
                    MovementsVo vo = MovementsVo.init(map.get(movement.getUserId()), movement);

                    //点赞标识
                    String key1 = Constants.MOVEMENTS_INTERACT_KEY + movement.getId();
                    String hashKey1 = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
                    if (redisTemplate.opsForHash().hasKey(key1, hashKey1)) {
                        vo.setHasLiked(1);
                    }
                    //喜欢标识
                    String key2 = Constants.MOVEMENTS_INTERACT_KEY + movement.getId();
                    String hashKey2 = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
                    if (redisTemplate.opsForHash().hasKey(key2, hashKey2)) {
                        vo.setHasLoved(1);
                    }

                    return vo;
                }).collect(Collectors.toList());
        //7、构造PageResult并返回
        return new PageResult(page, pagesize, 0L, vos);
    }
}
